<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>rendeer.js: shadowmap example</title>
	<link rel="stylesheet" type="text/css" href="style.css" />
	<style type='text/css'>
		html, body { width: 100%; height: 100%; margin: 0; padding: 0 }
	</style>
	<script type="text/javascript" src="../external/gl-matrix-min.js"></script>
	<script type="text/javascript" src="../external/litegl.js"></script>
	<script type="text/javascript" src="../build/rendeer.js"></script>

	<script id="shaders" type="x-shader/x-glsl">
\shaders

phong_shadow basic.vs phong_shadow.fs

\basic.vs 

	precision highp float;
	attribute vec3 a_vertex;
	attribute vec3 a_normal;
	attribute vec2 a_coord;

	varying vec3 v_wPosition;
	varying vec3 v_wNormal;
	varying vec2 v_coord;

	uniform mat4 u_viewprojection;
	uniform mat4 u_model;

	void main() {
		vec3 vertex = a_vertex;

		v_wPosition = (u_model * vec4(vertex,1.0)).xyz;
		v_wNormal = (u_model * vec4(a_normal,0.0)).xyz;
		v_coord = a_coord;

		gl_Position = u_viewprojection * vec4( v_wPosition, 1.0 );
		gl_PointSize = 2.0;
	}

\phong_shadow.fs

	precision highp float;

	varying vec3 v_wPosition;
	varying vec3 v_wNormal;
	varying vec2 v_coord;

	uniform vec3 u_camera_position;
	uniform vec4 u_background_color;
	uniform vec3 u_ambient_light;
	uniform vec3 u_light_color;
	uniform vec3 u_light_vector;

	uniform vec4 u_color;

	uniform mat4 u_shadowmap_matrix;
	uniform sampler2D u_shadowmap_texture;

	float testShadowmap( vec3 pos )
	{
		const float bias = 0.004;
		vec4 proj = u_shadowmap_matrix * vec4(pos, 1.0);
		vec2 sample = (proj.xy / proj.w) * vec2(0.5) + vec2(0.5);
		if(sample.x >= 0.0 && sample.x <= 1.0 && sample.y >= 0.0 && sample.y <= 1.0 )
		{
			float depth = texture2D( u_shadowmap_texture, sample ).x;
			if( depth > 0.0 && depth < 1.0 && depth <= ( ((proj.z-bias) / proj.w) * 0.5 + 0.5) )
				return 0.0;
		}
		return 1.0;
	}

	void main() {

		vec3 N = normalize( v_wNormal );

		//compute material
		vec4 material = u_color;

		//compute light
		float NdotL = max( dot( N, -u_light_vector ), 0.0 );
		vec3 light = u_ambient_light;
		float shadow = 1.0;
		shadow = testShadowmap( v_wPosition );
		light += shadow * u_light_color * NdotL;


		vec3 E = normalize(v_wPosition - u_camera_position);

		//final
		vec3 final_color = material.xyz * light;

		//fresnel
		final_color = mix( final_color, u_background_color.xyz, pow( 1.0 - abs(dot(N,reflect(E,N))), 1.1 ) );

		gl_FragColor = vec4( final_color, material.a );
	}
</script>

	<script type="text/javascript">
	
	function init()
	{
		//create a scene
		var scene = new RD.Scene();

		//create the rendering context
		var context = GL.create({width: window.innerWidth, height:window.innerHeight});
		var renderer = new RD.Renderer(context);
		document.body.appendChild(renderer.canvas); //attach

		//get shaders code from HTML (please, use the loadShaders system instead of embeding
		renderer.setShadersFromFile( document.getElementById("shaders").innerHTML );

		//create camera
		var camera = new RD.Camera();
		camera.perspective( 45, gl.canvas.width / gl.canvas.height, 1, 1000 );
		camera.lookAt( [0,200,300],[0,100,0],[0,1,0] );

		//create a root node
		var pivot = new RD.SceneNode();
		pivot.update = function(dt) { 
			this.rotate(dt * 0.2,RD.UP);
		}
		scene.root.addChild(pivot);

		//create the floor
		var floor = new RD.SceneNode();
		floor.color = [1,1,1,1];
		floor.mesh = "planeXZ"; //this mesh comes by default
		floor.scaling = 500;
		pivot.addChild(floor);

		//create the human
		var man = new RD.SceneNode();
		man.color = [1,1,1,1];
		man.mesh = "data/man.obj";
		pivot.addChild(man);

		//light with shadowmap 
		var light = {
			color: vec3.fromValues(1,1,1),
			position: vec3.create(),
			camera: new RD.Camera(),
			texture: new GL.Texture( 1024,1024, { format: gl.DEPTH_COMPONENT, type: gl.UNSIGNED_INT, filter: gl.NEAREST }),
			lookAt: function(eye, center, up) {
				this.position.set(eye);
				this.camera.lookAt( eye, center, up );
			}
		};
		light.fbo = new GL.FBO( null, light.texture );
		light.camera.orthographic(100,0,600,1);
		light.lookAt([300,400,0],[0,100,0],[0,1,0]);

		//global settings
		var bg_color = vec4.fromValues(0.2,0.3,0.4,1);

		var global_uniforms = { 
			u_camera_position: camera.position,
			u_background_color: bg_color,
			u_light_vector: light.camera.getFront(),
			u_light_color: vec3.fromValues(1,1,1),
			u_ambient_light: vec3.fromValues(0.3,0.4,0.5),
			u_shadowmap_matrix: light.camera._viewprojection_matrix,
			u_shadowmap_texture: 4
		};

		//main render loop
		var last = now = getTime();
		requestAnimationFrame(animate);
		function animate() {
			requestAnimationFrame( animate );

			last = now;
			now = getTime();
			var dt = (now - last) * 0.001;

			//generate shadowmap
			light.fbo.bind();
				gl.clear( gl.DEPTH_BUFFER_BIT );
				renderer.shader_overwrite = "flat";
				renderer.render( scene, light.camera );
			light.fbo.unbind();

			//render final pass
			light.texture.bind(4);
			renderer.shaders["phong_shadow"].uniforms( global_uniforms );
			renderer.shader_overwrite = "phong_shadow";
			renderer.clear(bg_color);
			renderer.render(scene, camera);

			//show texture in corner
			gl.drawTexture( light.texture, 10,10, 256,256 );

			//update
			scene.update(dt);
		}

		//input
		renderer.context.captureMouse();
		renderer.context.onmousemove = function(e)
		{
			if(e.dragging)
				pivot.rotate( e.deltax * 0.01, RD.UP );
		}
	}


	</script>
</head>
<body>
<script>init();</script>
</body>
</html>


